/*include guards*/
#ifndef L1_DATA_H
#define L1_DATA_H
//standard header files
#include "cacheline.h"
//Cache derived from parent CacheLine class
class Cache : public CacheLine
{
public:
    Cache() {}
    Cache(int l,int w);//parameterized constructor
    ~Cache();
    int lines;
    int ways;
    Cache **cache;

    void init(int proto);//Initialize or resets
    int checkTag(int index_local, int tag_local);// parameter names to help distinguish between the index and tag inherited from cache
    int checkLRU(int index);
    void updateLRU(int index, int ourway);
    int snoop(int index, int way);
    void update(int operation,int index,int way, int validbit);
};
//Parameterized constructor
Cache::Cache(int l,int w)
{
    lines=l;
    ways=w;
    Cache **cachea= new Cache*[lines];
    for(int i = 0; i < lines; ++i) {
        cachea[i] = new Cache[ways];
    }
    cache=cachea;
}
//destructor
Cache::~Cache()
{
    for(int i = 0; i < lines; ++i) {
        delete [] cache[i];
    }
    delete [] cache;
}
/* Initialize the LRU for cache
   LRU is set to the way
   validbit is initialized to invalid(0)
   Tag bits set to null */
void Cache::init (int protocol)
{
    for (int index = 0; index < lines; index++)
    {
        for (int way = 0; way < ways; way++)
        {
            cache[index][way].lruBits = way;
            cache[index][way].validbit = 0;//Invalid
            cache[index][way].tag = 0;
            cache[index][way].protocol=protocol;//Set as invalid
            cache[index][way].state=I;
        }
    }
}
/* check every way in the given index to see if the given tag exists*/
int Cache::checkTag(int index_local, int tag_local)
{
    int way_local;
    for (way_local = 0; way_local < ways; way_local++)
    {

        if (cache[index_local][way_local].tag == tag_local)
            return way_local;
    }
    return -1;//indicates not found
}
/*given an index, this function returns the least recently used way
 LRU bits of 0 give the least recently used way
 LRU bits of 'ways' give most recently used way*/
int Cache::checkLRU(int index)
{
    int way;
    for (way = 0; way < ways; way++)
    {
        if (cache[index][way].lruBits == ways-1)
            return way;
    }
// return ways;
}

// this function updates the LRU bits to reflect a new most recently used way
void Cache::updateLRU(int index, int ourway)
{
    // if the LRU bits of our way are already the most recently used, we do nothing
    if (cache[index][ourway].lruBits == 0)
        return;

    else
    {
        //int testbits = ourbits++;
        int testway;
        testway = 0;
        while (testway < ways)
        {
            if (cache[index][testway].lruBits < cache[index][ourway].lruBits)
            {
                cache[index][testway].lruBits++;
            }

            testway++;
        }

        cache[index][ourway].lruBits = 0;
    }

}


int Cache::snoop( int index,int way)
{
    return cache[index][way].validbit;
}
void Cache::update(int operation,int index, int way, int validbit)
{
    if(cache[index][way].protocol==0)
    {
        cache[index][way].validbit=cache[index][way].MI(operation);
    }
    else  if(cache[index][way].protocol==1)
    {
        cache[index][way].validbit=cache[index][way].MSI(operation);
    }
    else if(cache[index][way].protocol==2)
    {
        cache[index][way].validbit=cache[index][way].MESI(operation,validbit);
    }
}


#endif /* end of include guard: L1_DATA_H*/
